//
// Created by frank on 2021/11/10.
//

#include <jni.h>
#include <stdlib.h>
#include <iostream>
#include "timer.h"
#include "log.h"

using namespace std;

static const char* const DL_CLASS_NAME = "com/frank/sdk/Timer";

int registerNewCallback(JNIEnv *env, jobject clazz, jobject objListener, Timer* pTimer) {
    LOGD("registerNewCallback \n");
    JNIObj* mJniObj = nullptr;
    if(mJniObj == nullptr)
    {
        mJniObj = (JNIObj*)malloc(sizeof(JNIObj));
        if(mJniObj == nullptr){
            return -1;
        }
        memset(mJniObj, 0, sizeof(JNIObj));
//        JavaVM* jvm = NULL;
        env->GetJavaVM(&mJniObj->g_jvm);

        // 获取类信息
        mJniObj->g_class = env->FindClass(DL_CLASS_NAME);

        if(nullptr == mJniObj->g_class){
            return -1;
        }

        mJniObj->JNI_onTimer = env->GetMethodID(mJniObj->g_class, "onTimer",
                                                "()I");
        if(mJniObj->JNI_onTimer == nullptr){
            LOGE("GetMethodID JNI_onTimer is error");
        }

        if(objListener == nullptr){
            LOGE("DistributedPbServerJNI objListener is null");
        }else
        {
            mJniObj->g_obj = env->NewGlobalRef(objListener);
        }

        pTimer->SetJniObject(mJniObj);
    }

    return 0;

}


extern "C" jstring
Java_com_frank_sdk_MyStringUtil_getStringNDK(JNIEnv *env, jclass instance)
{
    string result = "Hello from SDK(C++)";
    return env->NewStringUTF(result.c_str());
}

void func2(int x)
{
    LOGI("trigger func2, x: %d", x);
}


extern "C"
JNIEXPORT void JNICALL
Java_com_frank_sdk_Timer_create(JNIEnv *env, jobject thiz) {
    // TODO: implement create()
    Timer* pTimer = new Timer();
    registerNewCallback(env, thiz, thiz, pTimer);

    jclass clazz = env->GetObjectClass(thiz);
    jfieldID  hanldeField = env->GetFieldID(clazz,"_handle", "J");
    env->SetLongField(thiz, hanldeField, reinterpret_cast<jlong>(pTimer));


    pTimer->start(1000, [=]() {
        auto pObj = pTimer->GetJniObject();
        JNIEnv* jniEnv = nullptr;
        if( pObj != nullptr) {
            pObj->g_jvm->AttachCurrentThread((&jniEnv), nullptr);
            if(jniEnv == nullptr){
                LOGE("onTimer attach current thread is error");
                return 0;
            }

            jint timestamp = jniEnv->CallIntMethod(pObj->g_obj, pObj->JNI_onTimer);
            LOGI("onTimer called, timestamp:%d", __func__ , timestamp);
        }
        //LOGI("onTimer called");
    });

//    pTimer->start(1000, std::bind(func2, 3));

}
extern "C"
JNIEXPORT void JNICALL
Java_com_frank_sdk_Timer_destroy(JNIEnv *env, jobject thiz) {
    // TODO: implement destroy()
    jclass clazz = env->GetObjectClass(thiz);
    jfieldID  handleField = env->GetFieldID(clazz,"_handle", "J");
    Timer* pTimer = reinterpret_cast<Timer *>(env->GetLongField(thiz, handleField));

    delete pTimer;

}